package com.papers.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.papers.common.core.domain.PageQuery;
import com.papers.common.core.domain.R;
import com.papers.common.core.page.TableDataInfo;
import com.papers.common.exception.ServiceException;
import com.papers.common.helper.LoginHelper;
import com.papers.common.utils.DateUtils;
import com.papers.common.utils.StringUtils;
import com.papers.system.domain.TJuanCourse;
import com.papers.system.domain.TJuanDepartment;
import com.papers.system.domain.TJuanMajor;
import com.papers.system.domain.bo.TJuanMajorBo;
import com.papers.system.domain.dto.TJuanMajorDto;
import com.papers.system.domain.vo.TJuanLeftTreeVo;
import com.papers.system.domain.vo.TJuanMajorOutVo;
import com.papers.system.domain.vo.TJuanMajorPutVo;
import com.papers.system.domain.vo.TJuanMajorVo;
import com.papers.system.mapper.TJuanCourseMapper;
import com.papers.system.mapper.TJuanDepartmentMapper;
import com.papers.system.mapper.TJuanMajorMapper;
import com.papers.system.service.ITJuanMajorService;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 专业Service业务层处理
 *
 * @author papers
 * @date 2022-10-08
 */
@RequiredArgsConstructor
@Service
public class TJuanMajorServiceImpl implements ITJuanMajorService {

    private final TJuanDepartmentMapper departmentMapper;
    private final TJuanMajorMapper baseMapper;
    private final TJuanCourseMapper tJuanCourseMapper;

    /**
     * 查询专业
     */
    @Override
    public TJuanMajorVo queryById(String majorId) {
        return baseMapper.getVoById(majorId);
    }

    /**
     * 查询专业列表
     */
    @Override
    public TableDataInfo<TJuanMajorVo> queryPageList(TJuanMajorDto dto, PageQuery pageQuery) {
        LambdaQueryWrapper<TJuanMajor> lqw = new LambdaQueryWrapper<>();
        lqw.orderByAsc(TJuanMajor::getMajorCode);
        Page<TJuanMajorVo> page;
        if ("-1".equals(dto.getDepartId())) {
            page = baseMapper.selectVoPage(pageQuery.build(), lqw);
        } else {
            page = baseMapper.getMajorByPage(pageQuery.build(), dto);
        }
        //Page<TJuanMajorVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }

    /**
     * 查询专业列表
     */
    @Override
    public List<TJuanMajorVo> queryList(TJuanMajorBo bo) {
        LambdaQueryWrapper<TJuanMajor> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<TJuanMajor> buildQueryWrapper(TJuanMajorBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TJuanMajor> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getDepartId()), TJuanMajor::getDepartId, bo.getDepartId());
        lqw.eq(StringUtils.isNotBlank(bo.getMajorCode()), TJuanMajor::getMajorCode, bo.getMajorCode());
        lqw.like(StringUtils.isNotBlank(bo.getMajorName()), TJuanMajor::getMajorName, bo.getMajorName());
        lqw.eq(StringUtils.isNotBlank(bo.getCreatedBy()), TJuanMajor::getCreatedBy, bo.getCreatedBy());
        lqw.eq(bo.getCreatedTime() != null, TJuanMajor::getCreatedTime, bo.getCreatedTime());
        lqw.eq(StringUtils.isNotBlank(bo.getUpdatedBy()), TJuanMajor::getUpdatedBy, bo.getUpdatedBy());
        lqw.eq(bo.getUpdatedTime() != null, TJuanMajor::getUpdatedTime, bo.getUpdatedTime());
        return lqw;
    }

    /**
     * 新增专业
     */
    @Override
    public Boolean insertByBo(TJuanMajorBo bo) {
        TJuanMajor add = BeanUtil.toBean(bo, TJuanMajor.class);

        add.setUpdatedBy(LoginHelper.getUsername());
        add.setCreatedBy(LoginHelper.getUsername());
        add.setCreatedTime(DateUtils.getNowDate());
        add.setUpdatedTime(DateUtils.getNowDate());

        LambdaQueryWrapper<TJuanMajor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TJuanMajor::getDepartId, bo.getDepartId())
                .orderByDesc(TJuanMajor::getMajorCode)
                .last("LIMIT 1");
        TJuanMajor major = baseMapper.selectOne(queryWrapper);

        LambdaQueryWrapper<TJuanDepartment> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TJuanDepartment::getDepartId, bo.getDepartId());
        TJuanDepartment department = departmentMapper.selectOne(lqw);
        String newCode;
        if (ObjectUtils.isNull(major)) {
            TJuanMajorBo majorBo = new TJuanMajorBo();
            majorBo.setMajorCode(department.getDepartCode() + "01");
            newCode = majorBo.getMajorCode();
        } else {
            List<String> majors = baseMapper.selectCodeList(bo.getDepartId());
            int oldCode = Integer.parseInt(major.getMajorCode().substring(3));
            if (oldCode != majors.size()) {
                int currentCode = 01;
                for (String item : majors) {
                    if (currentCode != Integer.parseInt(item)) {
                        oldCode = currentCode - 1;
                        break;
                    }
                    currentCode++;
                }
            }
            oldCode++;
            if (oldCode > 99) {
                throw new ServiceException("已达到专业最大数量，请联系管理员");
            }
            newCode = major.getMajorCode().substring(0, 3).concat(String.format("%02d", oldCode));
        }
        add.setMajorCode(newCode);

        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setMajorId(add.getMajorId());
        }
        return flag;
    }

    /**
     * 修改专业
     */
    @Override
    public Boolean updateByBo(TJuanMajorBo bo) {
        TJuanMajor update = BeanUtil.toBean(bo, TJuanMajor.class);
        update.setUpdatedBy(LoginHelper.getUsername());
        update.setUpdatedTime(DateUtils.getNowDate());
        return baseMapper.updateById(update) > 0;
    }


    /**
     * 批量删除专业
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        for (String id : ids) {
            QueryWrapper<TJuanCourse> queryWrapper = new QueryWrapper();
            queryWrapper.lambda().eq(TJuanCourse::getMajorId, id);
            List<TJuanCourse> list = tJuanCourseMapper.selectList(queryWrapper);
            if (list.size() > 0) {
                throw new ServiceException("该专业下有课程存在，删除失败");
            }
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 唯一约束
     */
    @Override
    public int MajorCodeUnique(TJuanMajorBo bo) {

        String majorCode = bo.getMajorCode();
        QueryWrapper<TJuanMajor> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(TJuanMajor::getMajorCode, majorCode);
        queryWrapper.last("LIMIT 1");
        TJuanMajorVo tJuanMajorVo = baseMapper.selectVoOne(queryWrapper);
        /*如存在相同code的对象，返回0*/
        if (tJuanMajorVo == null) {
            return 1;
        } else if (tJuanMajorVo.getMajorId().equals(bo.getMajorId())) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * 查询专业
     *
     * @param majorId
     * @return
     */
    @Override
    public TJuanMajor getOne(String majorId) {
        LambdaQueryWrapper<TJuanMajor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(null != majorId, TJuanMajor::getMajorName, majorId);
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    public TJuanMajor getMajorByCode(String majorCode) {
        LambdaQueryWrapper<TJuanMajor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(null != majorCode, TJuanMajor::getMajorName, majorCode);
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    public R getMajorBydepartmentId(String departmentId) {
        if (StringUtils.isNotBlank(departmentId)) {
            LambdaQueryWrapper<TJuanMajor> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TJuanMajor::getDepartId, departmentId);
            return R.ok(baseMapper.selectVoList(queryWrapper));
        }
        return R.fail("请选择一个院系");
    }

    /**
     * 导入专业
     *
     * @param list
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveBatch(List<TJuanMajorOutVo> list) {
        List<TJuanMajorOutVo> list1 = new ArrayList<>();
        List<TJuanMajorOutVo> list2 = new ArrayList<>();
        for (TJuanMajorOutVo item : list) {
            if (null != item.getMajorCode()) {
                list1.add(item);
            } else {
                list2.add(item);
            }
        }
        list1.addAll(list2);

        String newCode;
        for (TJuanMajorOutVo item : list1) {
            if (item.getMajorName() == null) {
                return R.fail("存在专业名称为空，请修改");
            }
            if (null != item.getDepartCode() && item.getDepartCode().substring(1).length() == 1) {
                item.setDepartCode("Y0" + item.getDepartCode().substring(1));
            }
            if (null != item.getMajorCode() && item.getMajorCode().substring(1).length() == 3) {
                item.setMajorCode("Y0" + item.getMajorCode());
            }
            LambdaQueryWrapper<TJuanDepartment> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(TJuanDepartment::getDepartCode, item.getDepartCode());
            TJuanDepartment department = departmentMapper.selectOne(lambdaQueryWrapper);
            if (ObjectUtils.isEmpty(department)) {
                return R.fail("院系编号错误或院系不存在，请修改");
            }

            //没有code
            if (ObjectUtils.isNull(item.getMajorCode())) {
                LambdaQueryWrapper<TJuanMajor> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TJuanMajor::getDepartId, department.getDepartId())
                        .orderByDesc(TJuanMajor::getMajorCode)
                        .last("LIMIT 1");
                TJuanMajor major = baseMapper.selectOne(queryWrapper);
                if (ObjectUtils.isNull(major)) {
                    newCode = department.getDepartCode() + "01";
                } else {
                    List<String> majors = baseMapper.selectCodeList(department.getDepartId());
                    int oldCode = Integer.parseInt(major.getMajorCode().substring(3));
                    if (oldCode != majors.size()) {
                        int currentCode = 01;
                        for (String code : majors) {
                            if (currentCode != Integer.parseInt(code.substring(3))) {
                                oldCode = currentCode - 1;
                                break;
                            }
                            currentCode++;
                        }
                    }
                    oldCode++;
                    if (oldCode > 99) {
                        return R.fail("已达到专业最大数量，请联系管理员");
                    }
                    newCode = major.getMajorCode().substring(0, 3).concat(String.format("%02d", oldCode));
                }
                item.setMajorCode(newCode);
                item.setDepartId(department.getDepartId());
                item.setCreatedBy(LoginHelper.getUsername());
                item.setCreatedTime(DateUtils.getNowDate());
            }
            //有code
            else {
                if (!item.getDepartCode().equals(item.getMajorCode().substring(0, 3))) {
                    return R.fail("存在院系编号与专业编号不匹配，请修改后导入");
                }
                if (item.getMajorCode().length() != 5) {
                    return R.fail("存在专业编号格式有误，请修改后导入");
                }
                //如果code相同就是覆盖更新，设置相同的专业id
                LambdaQueryWrapper<TJuanMajor> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TJuanMajor::getMajorCode, item.getMajorCode());
                TJuanMajor major = baseMapper.selectOne(queryWrapper);
                //重复，更新信息
                if (major != null) {
                    item.setDepartId(major.getDepartId());
                    item.setMajorId(major.getMajorId());
                }
                //没有重复，新增
                else {
                    item.setDepartId(department.getDepartId());
                    item.setCreatedBy(LoginHelper.getUsername());
                    item.setCreatedTime(DateUtils.getNowDate());
                }
            }
            item.setUpdatedBy(LoginHelper.getUsername());
            item.setUpdatedTime(DateUtils.getNowDate());
            TJuanMajor tJuanMajor = BeanUtil.copyProperties(item, TJuanMajor.class);
            baseMapper.insertOrUpdate(tJuanMajor);
        }
        return R.ok("导入成功");
    }

    /**
     * 查询专业树
     *
     * @return
     */
    @Override
    public List<TJuanLeftTreeVo> getDeptTreeList(String departId) {
        List<TJuanLeftTreeVo> departTreeList = departmentMapper.getDepartTreeList();
        departTreeList.stream().map(item -> {
            item.setParentId("0");
            return item;
        }).collect(Collectors.toList());
        // 递归获取树
        List<TJuanLeftTreeVo> list = getChildrenList(departTreeList, "0");
        return list;
    }

    /**
     * 递归获取 树
     *
     * @param treeList
     * @param id
     * @return
     */
    private List<TJuanLeftTreeVo> getChildrenList(List<TJuanLeftTreeVo> treeList, String id) {
        List<TJuanLeftTreeVo> children = new ArrayList<>();
        for (TJuanLeftTreeVo leftTreeVo : treeList) {
            // 判断该节点的父id，是否与传入的父id相同，相同则递归设置其子节点，并将该节点放入children集合中
            if (StringUtil.equals(leftTreeVo.getParentId(), id)) {
                // 递归设置其子节点
                leftTreeVo.setChildren(getChildrenList(treeList, leftTreeVo.getId()));
                // 放入children集合
                children.add(leftTreeVo);
            }
        }
        return children;
    }

    /**
     * 导出专业
     *
     * @return
     */
    @Override
    public List<TJuanMajorPutVo> OutputList() {
        return baseMapper.OutputMajor();
    }
}
